"""
Helpers for using the hmmbuild program.
"""

from ssummo import CONFIG

import multiprocessing
import sys

from Bio import SeqIO


class HmmbuildProcess(multiprocessing.Process):
    """Runs the hmmbuild asynchronously, allowing multiple hmmbuild processes to
    be run simultaneously.

    The process is controlled through
    """

    def __init__(self, semaphore):
        """
        :param semaphore: A :class:`multiprocessing.Semaphore` instance, for
                          limiting the number of active processes.
        """
        from os.path import join, sep
        multiprocessing.Process.__init__(self)
        #self.inQueue = multiprocessing.Queue()
        self._info_queue = multiprocessing.Queue()
        #: Input queue.
        (in_seq_pipe, out_seq_pipe) = multiprocessing.Pipe()
        self._in_seq_pipe = in_seq_pipe
        self._out_seq_pipe = out_seq_pipe
        #self.inSeqPipe, self.__outSeqs = multiprocessing.Pipe()
        self._sem = semaphore
        #: semaphore
        self.hmmbuild = join(CONFIG.hmmerdir,
                             CONFIG.hmmbuildCMD.rsplit(sep, 1)[-1])
        #: hmmer command

    def acquire(self):
        """Increment the counter on the shared semaphore: :data:`self._sem`"""
        self._sem.acquire()

    def put_info(self, info):
        """Used by controlling threads, to send required options to the hmmbuild
        process.

        :param info: A sequence of the form: ``(hmm_path, nseqs, taxid)``."""
        self._info_queue.put(info)

    def send_seq(self, seq):
        """Used by controlling threads, to send sequences to the hmmbuild
        processes stdin stream.

        :param seq: Biopython :class:`SeqRecord.SeqRecord` instance.
        """
        self._in_seq_pipe.send(seq)

    def run(self):
        from subprocess import Popen, PIPE
        (HMMPath, nseqs, taxid) = self._info_queue.get()
        hmmbuild = self.hmmbuild
        recv = self._out_seq_pipe.recv
        release = self.sem.release
        while HMMPath != 'STOP':
            # hmmbuild options
            cmd = [hmmbuild, '-n', taxid, '--rna', '--informat',
                   'stockholm', HMMPath, '-']
            # infernal options:
            # cmd = [hmmbuild, '-n', taxid, '--iins', '--ignorant',
            #        '--informat', 'stockholm', HMMPath, '-' ]
            process = Popen(cmd, shell=False, stdin=PIPE, stdout=PIPE,
                            stderr=PIPE, bufsize=-1)
            SeqIO.write([recv() for seqRec in xrange(nseqs)],
                        process.stdin, 'stockholm')
            process.stdin.flush()
            process.stdin.close()
            retCode = process.wait()
            release()   # Reduce semaphore count
            if retCode != 0:
                sys.stderr.write( "HMMBuild error!" + '\n')
                sys.stderr.write( process.stderr.read() + '\n')
                sys.stderr.flush()
                process.stdout.read()
            else:
                process.communicate()
                #null = process.stdout.read(), process.stderr.read()
                #del(null)
            HMMPath, nseqs, taxid = self._info_queue.get()
